home *** CD-ROM | disk | FTP | other *** search
/ Libris Britannia 4 / science library(b).zip / science library(b) / CUGUK / COMMS / C022.ZIP / LS.C < prev    next >
Text File  |  1990-01-31  |  16KB  |  739 lines

  1. /************************************************************************
  2.  * C Users Group (U.K) C Source Code Library File    0        *
  3.  * Inquiries to: M. Houston, 36 Whetstone Clo. Farquhar Rd.        *
  4.  * Edgbaston, Birmingham B15 2QN ENGLAND                *
  5.  ************************************************************************
  6.  * File name:    ls.c                            *
  7.  * Program  :    ls                            *
  8.  *                                     *
  9.  * Source   :    Minix utility, modified by A Godwin            *
  10.  * Purpose  :    directory listing program                *
  11.  * Changes  :                                *
  12.  *                                    *
  13.  * 12.06.88    A Godwin - modified version released to CUG        *
  14.  ************************************************************************/
  15.  
  16. /* ls - list files and directories     Author: Andy Tanenbaum 
  17.  *
  18.  * Changes:
  19.  *
  20.  *    Produce columnar output on tty.
  21.  *     fix bug with unterminated maximum-length filenames.
  22.  *                            - artg 1.1.88
  23.  */
  24.  
  25.  
  26. #include "../h/const.h"
  27. #include "../h/type.h"
  28. #include "stat.h"
  29. #include "../fs/const.h"
  30. #include "../fs/type.h"
  31. #include "stdio.h"
  32.  
  33. #define DIRNAMELEN        14    /* # chars in a directory entry name */
  34. #define NFILE            256    /* max files in arg list to ls */
  35. #define MAXPATHLEN       256    /* max chars in a path name */
  36. #define NDIRBLOCKS        16    /* max length of a directory */
  37. #define LEGAL      0x1E096DL    /* legal flags to ls */
  38. #define SCWIDTH           79    /* screen width for column formatting */
  39.  
  40.  
  41. struct file {
  42.   char *name;
  43.   unsigned short mode;
  44.   unsigned short f_uid;
  45.   unsigned short f_gid;
  46.   unsigned short inumber;
  47.   long modtime;
  48.   long size;
  49.   short link;
  50. } file[NFILE+1];
  51.  
  52. struct dir {
  53.   short inum;
  54.   char dirname[DIRNAMELEN];
  55. } dir[INODES_PER_BLOCK*NDIRBLOCKS];
  56.  
  57. int nrfiles;
  58. char linebuf[BLOCK_SIZE];    /* for reading passwd file */
  59. int linenext;
  60. int linelimit;
  61. int topfiles;            /* nr of files in ls command */
  62. int passwd;            /* file descr for /etc/passwd or /etc/group */
  63. short sort_index[NFILE];
  64. long flags;
  65. int  cflag = 1;            /* column output flag - set for tty */
  66. int lastuid = -1;
  67. char lastname[10];
  68. char buffer[BUFSIZ];
  69.  
  70. char *rwx[] =    {"---", "--x", "-w-", "-wx", "r--", "r-x", "rw-", "rwx",
  71.          "--s", "--s", "-ws", "-ws", "r-s", "r-s", "rws", "rws"};
  72. char *null = {"."};
  73. extern long get_flags();
  74. extern char *getuidgid();
  75. extern int errno;
  76.  
  77.  
  78. main(argc, argv)
  79. int argc;
  80. char *argv[];
  81. {
  82.   int expand_flag;        /* allows or inhibits directory expansion */
  83.   char *pwfile;
  84.   struct stat sbuf;
  85.  
  86.   setbuf(stdout, buffer);
  87.   expand_flag = 1;
  88.   flags = get_flags(argc, argv);
  89.   expand_args(argc, argv);
  90.  
  91.   /* force single-column output if -l flag or stdout is not a tty */
  92.   if (present('l') || !isatty(1))
  93.     cflag = 0;
  94.  
  95.   if (topfiles == 0) {
  96.     file[NFILE].name = null;
  97.     exp_dir(&file[NFILE]);
  98.     expand_flag = 0;
  99.   }
  100.   if (present('f')) flags = 0x21;    /* -f forces other flags on and off */
  101.   sort(0, nrfiles, expand_flag);
  102.  
  103.   if (present('l')) {
  104.     if (present('g'))
  105.         pwfile = "/etc/group";
  106.     else
  107.         pwfile = "/etc/passwd";
  108.     passwd = open(pwfile, 0);
  109.     if (passwd < 0) fprintf(stdout, "Can't open %s\n", pwfile);
  110.   }
  111.  
  112.   if (topfiles == 0) print_total(0, nrfiles);
  113.   print(0, nrfiles, expand_flag, "");
  114.   fflush(stdout);
  115.   exit(0);
  116. }
  117.  
  118.  
  119.  
  120. expand_args(argc, argv)
  121. int argc;
  122. char *argv[];
  123. {
  124. /*  Put each argument presented to ls in a 'file' entry. */
  125.  
  126.   int k, statflag;
  127.  
  128.   k = argc - topfiles;
  129.   statflag = (topfiles == 0 ? 0 : 1);
  130.   if (present('c') || present('t') || present('u')) statflag = 1;
  131.   if (present('s') || present('l')) statflag = 1;
  132.   while (k < argc) fill_file("", argv[k++], statflag);
  133. }
  134.  
  135.  
  136.  
  137.  
  138.  
  139. sort(index, count, expand_flag)
  140. int index, count, expand_flag;
  141. {
  142. /* Sort the elements file[index] ... file[index+count-1] as needed. */
  143.  
  144.   int i, j, tmp;
  145.  
  146.   if (count == 0) return;
  147.   for (i = index; i < index + count; i++) sort_index[i] = i;
  148.   if (present('f')) return;    /* -f inhibits any sorting */
  149.  
  150.   for (i = index; i < index + count - 1; i++)
  151.     for (j = i + 1; j < index + count; j++) {
  152.         if (reversed(sort_index[i], sort_index[j], expand_flag)) {
  153.             /* Swap two entries */
  154.             tmp = sort_index[j];
  155.             sort_index[j] = sort_index[i];
  156.             sort_index[i] = tmp;
  157.         }
  158.     }
  159. }
  160.  
  161.  
  162.  
  163.  
  164.  
  165. int reversed(i, j, expand_flag)
  166. int i, j, expand_flag;
  167. {
  168. /* Return 1 if elements 'i' and 'j' are reversed, else return 0. */
  169.  
  170.   int r, m1, m2;
  171.   struct file *fp1, *fp2;
  172.  
  173.   fp1 = &file[i];
  174.   fp2 = &file[j];
  175.   if (expand_flag) {
  176.     if (fp1->size == -1L || fp2->size == -1L) {
  177.         fprintf(stdout, "ls: internal bug: non-stat'ed file in reversed()\n");
  178.         fflush(stdout);
  179.         exit(1);
  180.     }
  181.     m1 = fp1->mode & I_TYPE;
  182.     m2 = fp2->mode & I_TYPE;
  183.     if (m1 == I_DIRECTORY && m2 != I_DIRECTORY) return(1);
  184.     if (m1 != I_DIRECTORY && m2 == I_DIRECTORY) return(0);
  185.   }
  186.  
  187.   r = present('r');
  188.   if (present('t') || present('u')) {
  189.     /* Sort on time field. */
  190.     if (fp1->modtime > fp2->modtime)
  191.         return(r);
  192.     else
  193.         return(1-r);
  194.   } else {
  195.     /* Sort alphabetically. */
  196.     if (strlower(fp1->name, fp2->name, MAXPATHLEN))
  197.         return(r);
  198.     else
  199.         return(1-r);
  200.   }
  201. }
  202.  
  203.  
  204.  
  205.  
  206.  
  207. int strlower(s1, s2, count)
  208. char *s1, *s2;
  209. int count;
  210. {
  211. /* Return 1 is s1 < s2 alphabetically, else return 0. */
  212.  
  213.   while (count--) {
  214.     if (*s1 == 0 && *s2 == 0) return(1);
  215.     if (*s1 == 0) return(1);
  216.     if (*s2 == 0) return(0);
  217.     if (*s1 < *s2) return(1);
  218.     if (*s1 > *s2) return(0);
  219.     s1++;
  220.     s2++;
  221.   }
  222.  
  223.   /* The strings are identical up to the given length. */
  224.   return(1);
  225. }
  226.  
  227.  
  228.  
  229.  
  230.  
  231. print(index, count, expand, dirname)
  232. int index, count, expand;
  233. char *dirname;
  234. {
  235. /*  If an entry is a file, print it; if a directory, process it. */
  236.  
  237.   int k, m, nrf, from, len, maxlen = 0;
  238.   struct file *fp;
  239.  
  240.   nrf = nrfiles;
  241.   for (k = from = index; k < index + count; k++) {
  242.     fp = &file[sort_index[k]];
  243.     if (present('l') || present('s') || present('i'))
  244.         if (fp->size == -1L)    /* -1 means stat not done */
  245.             if (stat_file(dirname, fp) < 0) continue;
  246.  
  247.     m = fp->mode & I_TYPE;    /* 'm' may be junk if 'expand' = 0 */
  248.     if (present('f')) m = I_DIRECTORY;
  249.     if (m != I_DIRECTORY || present('d') || expand == 0) {
  250.  
  251.         len = strlen(fp->name);
  252.         maxlen = (len > maxlen ? len : maxlen);
  253.  
  254.         /* List a single line, if columns not needed */
  255.         if (!cflag)
  256.             print_line(fp,TRUE);
  257.  
  258.     } else {
  259.         /* Expand and print directory. */
  260.         if (cflag)        /* write files so far */
  261.             col_flush(from, k, maxlen);
  262.         from = k + 1;
  263.         maxlen = 0;
  264.         exp_dir(fp);
  265.         sort(nrf, nrfiles - nrf, 0);
  266.         if (topfiles > 1) fprintf(stdout, "\n%s:\n", fp->name);
  267.         print_total(nrf, nrfiles - nrf);
  268.         print(nrf, nrfiles - nrf, 0, fp->name); /* recursion ! */
  269.         nrfiles = nrf;
  270.     }
  271.   }
  272.   if (cflag)
  273.     col_flush(from, k, maxlen);        /* write out columns */
  274. }
  275.  
  276.  
  277.  
  278.  
  279.  
  280. exp_dir(fp)
  281. struct file *fp;
  282. {
  283. /* List the files within a directory.  Read whole dir in one blow.
  284.  * Expand and print whole dir in core, since 'file' struct has pointers to it.
  285.  *
  286.  * Fix : to ensure names in file array are nul-terminated, nul-terminate
  287.  * them in the dir structure ... this overwrites part of the following entry,
  288.  * so be rather careful.
  289.  */
  290.  
  291.   int n, fd, k, klim, suppress, statflag, exists, nextexists;
  292.   char *p;
  293.  
  294.  
  295.   fd = open(fp->name, 0);
  296.   if (fd < 0) {
  297.     fprintf(stdout, "Cannot list contents of %s\n", fp->name);
  298.     return;
  299.   }
  300.  
  301.   suppress = !present('a');
  302.   n = read(fd, dir, INODE_SIZE * INODES_PER_BLOCK * NDIRBLOCKS);
  303.   klim = (n + DIRNAMELEN + 1)/(DIRNAMELEN + 2);
  304.   if (n == INODE_SIZE * INODES_PER_BLOCK * NDIRBLOCKS) {
  305.     fprintf(stdout, "Directory %s too long\n", fp->name);
  306.     return;
  307.   }
  308.   statflag = 0;
  309.   if (present('c') || present('t') || present('u')) statflag = 1;
  310.   if (present('s') || present('l')) statflag = 1;
  311.  
  312.   nextexists = dir[0].inum;
  313.   for (k = 0; k < klim; k++) {
  314.  
  315.     exists = nextexists;
  316.     nextexists = dir[k+1].inum;    /* save from trashing */
  317.     if (exists != 0) {
  318.  
  319.         p = dir[k].dirname;
  320.         p[DIRNAMELEN] = '\0';    /* trashes NEXT inode number */
  321.  
  322.         if (suppress) {
  323.             if (*p == '.' && *(p+1) == 0) continue;
  324.             if (*p == '.' && *(p+1) == '.' && *(p+2) == 0) continue;
  325.         }
  326.         fill_file(fp->name, p, statflag);
  327.     }
  328.   }
  329.   close(fd);
  330. }
  331.  
  332.  
  333.  
  334.  
  335.  
  336. fill_file(prefix, postfix, statflag)
  337. char *prefix, *postfix;
  338. int statflag;
  339. {
  340. /* Fill the next 'file' struct entry with the file whose name is formed by
  341.  * concatenating 'prefix' and 'postfix'.  Stat only if needed.
  342.  */
  343.  
  344.   struct file *fp;
  345.  
  346.   if (nrfiles == NFILE) {
  347.     fprintf(stdout, "ls: Out of space\n");
  348.     fflush(stdout);
  349.     exit(1);
  350.   }
  351.   fp = &file[nrfiles++];
  352.   fp->name = postfix;
  353.   if(statflag) {
  354.     if (stat_file(prefix, fp) < 0) nrfiles--;
  355.   } else {
  356.     fp->size = -1L;        /* mark file as not yet stat'ed */
  357.   }
  358. }
  359.  
  360.  
  361.  
  362.  
  363. print_line(fp,end)        /* print line to stdout */
  364. struct file *fp;
  365. int end;
  366. {
  367.   int blks, m, prot, s;
  368.   char *p1, *p2, *p3, c;
  369.  
  370.   if (present('i')) fprintf(stdout, "%5d ", fp->inumber);
  371.  
  372.   if (present('s')) {
  373.     /* Print file size */
  374.     blks = nblocks(fp->size);
  375.     fprintf(stdout, "%4d ", blks);
  376.   }
  377.  
  378.   if (present('l')) {
  379.     m = fp->mode & I_TYPE;
  380.     if (m == I_DIRECTORY) c = 'd';
  381.     else if (m == I_BLOCK_SPECIAL) c = 'b';
  382.     else if (m == I_CHAR_SPECIAL) c = 'c';
  383.     else c = '-';
  384.  
  385.     m = fp->mode & 07777;
  386.     prot = (m >> 6) & 07;
  387.     if (m & I_SET_UID_BIT) prot += 8;
  388.     p1 = rwx[prot];
  389.  
  390.     prot = (m >> 3) & 07;
  391.     if (m & I_SET_GID_BIT) prot += 8;
  392.     p2 = rwx[prot];
  393.  
  394.     prot = m & 07;
  395.     p3 = rwx[prot];
  396.  
  397.     fprintf(stdout, "%c%s%s%s %2d ",c, p1, p2, p3, fp->link);
  398.  
  399.     /* Print owner or group */
  400.     owngrp(fp);
  401.  
  402.     m = fp->mode & I_TYPE;
  403.     if (m == I_CHAR_SPECIAL || m == I_BLOCK_SPECIAL) {
  404.         s = (short) fp->size;
  405.         fprintf(stdout, "%2d, %2d ", (s>>8)&0377, s&0377);
  406.     } else {
  407.         fprintf(stdout, "%8D ", fp->size);
  408.     }
  409.     date(fp->modtime);
  410.   }
  411.  
  412.   /* Print file name. */
  413.   fprintf(stdout, "%s%s",fp->name,(end ? "\n" : ""));
  414. }
  415.  
  416.  
  417.  
  418.  
  419. col_flush(from,to,len)    /* write out a section of file names, in cols */
  420. int from, to, len;
  421. {
  422.   int i, end, ents, cols, rows, row, col, rem, addlen, colinc;
  423.   struct file *fp;
  424.  
  425.   /* len is the length of the filename only. 
  426.    * Work out width of additional space needed. 
  427.    */
  428.  
  429.   addlen = 2;
  430.   if (present('i')) addlen += 6;
  431.   if (present('s')) addlen += 5;
  432.  
  433.   ents = to - from;
  434.   cols = SCWIDTH/(len + addlen);
  435.   cols = cols ? cols : 1;
  436.   len += (SCWIDTH - (len+addlen)*cols)/(cols-1);
  437.   rows = (ents+cols-1)/cols;
  438.   rem  = (ents%cols ? ents%cols : cols);
  439.  
  440.   /* format them out, 'cols' entries to a line */
  441.   for (row = 0; row < rows; row++) {
  442.     for (colinc = from, col = 0; col < cols && ents-- > 0; col++) {
  443.  
  444.         fp = &file[sort_index[colinc + row]];
  445.         colinc += (col < rem) ? rows : rows - 1;
  446.         end = (col + 1 == cols || ents == 0);
  447.         print_line(fp, end);
  448.  
  449.         /* pad names with spaces, except at line end */
  450.         if (!end)
  451.             for(i = 2 + len - strlen(fp->name); i; --i)
  452.                 putchar(' ');
  453.     }
  454.   }
  455. }
  456.  
  457. owngrp(fp)
  458. struct file *fp;
  459. {
  460.   char *buf;
  461.   int xid;
  462.  
  463.   if (present('g')) {
  464.     xid = fp->f_gid;
  465.   } else {
  466.     xid = fp->f_uid;
  467.   }
  468.   buf = getuidgid(xid);
  469.   if (buf != 0)
  470.     fprintf(stdout, "%6s ",buf);
  471.   else
  472.     fprintf(stdout, "%6d ",xid);
  473. }
  474.  
  475.  
  476.  
  477.  
  478.  
  479. int stat_file(prefix, fp)
  480. char *prefix;
  481. struct file *fp;
  482. {
  483. /* Stat a file and enter it in 'file'. */
  484.  
  485.   char namebuf[MAXPATHLEN], *p, *org, *q;
  486.   struct stat sbuf;
  487.   int m, ctr;
  488.  
  489.   /* Construct the full path name in 'namebuf'. */
  490.   p = namebuf;
  491.   q = prefix;
  492.   while (*q != 0 && p - namebuf < MAXPATHLEN) *p++ = *q++;
  493.   if (*prefix != 0) *p++ = '/';
  494.   org = fp->name;
  495.   q = fp->name;
  496.   ctr = 0;
  497.   while (*q != 0 && p - namebuf < MAXPATHLEN) {
  498.     ctr++;
  499.     if (*q == '/') ctr = 0;
  500.     if (ctr > DIRNAMELEN) break;
  501.     *p++ = *q++;
  502.   }
  503.   *p = 0;
  504.  
  505.   /* The name has been built.  Stat the file and copy the info. */
  506.   if ((m = stat(namebuf, &sbuf)) < 0) {
  507.     fprintf(stdout, "%s not found\n", namebuf);
  508.     return(-1);
  509.   }
  510.  
  511.   m = sbuf.st_mode & I_TYPE;
  512.   fp->mode = sbuf.st_mode;
  513.   fp->f_uid = sbuf.st_uid;
  514.   fp->f_gid = sbuf.st_gid;
  515.   fp->inumber = sbuf.st_ino;
  516.   fp->modtime = sbuf.st_mtime;
  517.   fp->size = sbuf.st_size;
  518.   fp->size = (m == I_CHAR_SPECIAL || m == I_BLOCK_SPECIAL ? sbuf.st_rdev : sbuf.st_size);
  519.   fp->link = sbuf.st_nlink;
  520.  
  521.   return(0);
  522. }
  523.  
  524.  
  525.  
  526.  
  527. long get_flags(argc, argv)
  528. int argc;
  529. char *argv[];
  530. {
  531. /* Get the flags. */
  532.   long fl, t;
  533.   int k, n;
  534.   char *ptr;
  535.  
  536.   fl = 0L;
  537.   n = 1;
  538.   topfiles = argc - 1;
  539.   while (n < argc) {
  540.     ptr = argv[n];
  541.     if (*ptr != '-') return(fl);
  542.     topfiles--;
  543.     ptr++;
  544.  
  545.     while (*ptr != 0) {
  546.         if (*ptr == '1') {
  547.             cflag = 0;    /* single column output */
  548.             ptr++;
  549.             continue;
  550.         }
  551.         k = *ptr - 'a';
  552.         t = 1L << k;
  553.         if (*ptr < 'a' || *ptr > 'z' || (t|LEGAL) != LEGAL) {
  554.             fprintf(stdout, "Bad flag: %c\n", *ptr);
  555.             ptr++;
  556.             continue;
  557.         }
  558.         fl |= t;
  559.         ptr++;
  560.     }
  561.     n++;
  562.   }
  563.   return(fl);
  564. }
  565.  
  566. present(let)
  567. char let;
  568. {
  569.   return  (int)((flags >> (let - 'a')) & 01);
  570. }
  571.  
  572.  
  573.  
  574.  
  575.  
  576. #define YEAR  (365L * 24L * 3600L)
  577. #define LYEAR (366L * 24L * 3600L)
  578.  
  579. int mo[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
  580. long curtime;
  581. char *moname[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
  582.           "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
  583.  
  584.  
  585. date(t)
  586. long t;                /* time in seconds */
  587. {
  588. /* Print the date.  This only works from 1970 to 2099. */
  589.  
  590.   int i, year, day, month, hour, minute;
  591.   long length, time(), original;
  592.  
  593.   year = 1970;
  594.   original = t;
  595.   while (t > 0) {
  596.     length = (year % 4 == 0 ? LYEAR : YEAR);
  597.     if ( t < length) break;
  598.     t -= length;
  599.     year++;
  600.   }
  601.  
  602.   /* Year has now been determined.  Now the rest. */
  603.   day = t/(24L * 3600L);
  604.   t -= (long) day * 24L * 3600L;
  605.   hour = t/3600L;
  606.   t -= 3600L * (long) hour;
  607.   minute = (int) t/60L;
  608.  
  609.   /* Determine the month and day of the month. */
  610.   mo[1] = (year % 4 == 0 ? 29 : 28);
  611.   month = 0;
  612.   i = 0;
  613.   while (day >= mo[i]) {
  614.     month++;
  615.     day -= mo[i];
  616.     i++;
  617.   }
  618.  
  619.   /* At this point, 'year', 'month', 'day', 'hour', 'minute'  ok */
  620.   if (curtime == 0) curtime = time( (long*)0);    /* approximate current time */
  621.   fprintf(stdout, "%3s %2d ",moname[month], day+1);
  622.   if (curtime - original >= YEAR/2L) {
  623.     fprintf(stdout, "%5d ",year);
  624.   } else {
  625.     if (hour < 10)
  626.         fprintf(stdout, "0%d:",hour);
  627.     else
  628.         fprintf(stdout, "%2d:",hour);
  629.  
  630.     if (minute < 10)
  631.         fprintf(stdout, "0%d ",minute);
  632.     else
  633.         fprintf(stdout, "%2d ",minute);
  634.   }
  635. }
  636.  
  637. print_total(index, count)
  638. int index, count;
  639. {
  640.   int blocks, i;
  641.  
  642.  
  643.   if (!present('l') && !present('s')) return;
  644.   blocks = 0;
  645.   for (i = index; i < index + count; i++) blocks += nblocks(file[i].size);
  646.   fprintf(stdout, "total %d\n", blocks);
  647. }
  648.  
  649.  
  650. char getpwdch()
  651. {
  652.   if (linenext == linelimit) {
  653.     /* Fetch another block of passwd file. */
  654.     linelimit = read(passwd, linebuf, BLOCK_SIZE);
  655.     linenext = 0;
  656.     if (linelimit <= 0) return (char) 0;
  657.   }
  658.   return (linebuf[linenext++]);
  659. }
  660.  
  661.  
  662. getline(buf)
  663. char *buf;
  664. {
  665.   while (1) {
  666.     *buf = getpwdch();
  667.     if (*buf == 0 || *buf == '\n') break;
  668.     buf++;
  669.   }
  670.   *buf = 0;
  671. }
  672.  
  673. char *getuidgid(usrid)
  674. int usrid;
  675. {
  676.   char lbuf[100], *ptr, *ptr1;
  677.   int bin;
  678.  
  679.   if (usrid == lastuid) return(lastname);
  680.   lseek(passwd, 0L, 0);        /* rewind the file */
  681.   linenext = 0;
  682.   linelimit = 0;
  683.   
  684.   /* Scan the file. */
  685.   while (1) {
  686.     ptr = lbuf;
  687.     while (ptr < &lbuf[100]) *ptr++ = 0;
  688.     getline(lbuf);
  689.     if (lbuf[0] == 0) return(0);
  690.  
  691.     /* Scan this line for uid/gid */
  692.     ptr = lbuf;
  693.     while (*ptr != ':' && *ptr != 0) ptr++;
  694.     if (*ptr == 0) return(0);
  695.     *ptr++ = 0;
  696.     while (*ptr != ':' && *ptr != 0) ptr++;
  697.     if (*ptr == 0) return(0);
  698.     ptr++;
  699.  
  700.     /* Ptr now points at a uid.  Convert it to binary. */
  701.     bin = 0;
  702.     while (*ptr != ':' && *ptr != 0 && *ptr != '\n') {
  703.         bin = 10*bin + (*ptr - '0');
  704.         ptr++;
  705.     }
  706.     if (bin == usrid) {
  707.         /* Hit. */
  708.         lastuid = usrid;
  709.         ptr = lastname;
  710.         ptr1 = lbuf;
  711.         while (*ptr++ = *ptr1++) ;
  712.         *ptr++ = 0;
  713.         return(lastname);
  714.     }
  715.   }
  716. }
  717.  
  718.  
  719.  
  720. nblocks(size)
  721. long size;
  722. {
  723. /* Convert file length to blocks, including indirect blocks. */
  724.  
  725.   int blocks, fileb;
  726.  
  727.   fileb = (size + (long) BLOCK_SIZE - 1)/BLOCK_SIZE;
  728.   blocks = fileb;
  729.   if (fileb <= NR_DZONE_NUM) return(blocks);
  730.   blocks++;
  731.   fileb -= NR_DZONE_NUM;
  732.   if (fileb <= NR_INDIRECTS) return(blocks);
  733.   blocks++;
  734.   fileb -= NR_INDIRECTS;
  735.   blocks += (fileb + NR_INDIRECTS - 1)/NR_INDIRECTS;
  736.   return(blocks);
  737. }
  738.  
  739.